<template>
  <div class="slider-wrap">
    <div class="slider-content" @touchstart="onTouchstart" @touchmove="onTouchmove" @touchend="onTouchend">
      <slot></slot>
    </div>
    <div class="slider-control" v-show="hasSlider">
      <transition name="fade">
        <div class="control-item" v-show="needSlide && moving && slideType === 'touch'"></div>
      </transition>
      <span class="slider-prev"
        v-show="detailMode && (needSlide || prePage) && slideType === 'click'"
        :class="{disabled: 0 === offsetX && !prePage}"
        @click="slidePrev"
      ></span>
      <i class="slider-prev-mask"
        v-show="detailMode && (needSlide || prePage) && slideType === 'click' && offsetX < 0"
      ></i>
      <span class="slider-next"
        v-show="detailMode && (needSlide || nextPage) && slideType === 'click'"
        :class="{disabled: offsetX === sliderMax && !nextPage}"
        @click="slideNext"
      ></span>
      <i class="slider-next-mask"
        v-show="detailMode && (needSlide || nextPage) && slideType === 'click' && offsetX > sliderMax"
      ></i>
    </div>
  </div>
</template>

<script>
let flag = !1
export default {
  name: 'ListSlider',
  props: {
    // 自动定位到对应索引项
    autoIndex: {
      type: Number,
      default: 0
    },
    // 内容子项数量
    length: {
      type: Number,
      required: !0
    },
    slideType: {
      type: String,
      default: 'touch'
    },
    canReset: {
      type: Boolean,
      default: !1
    },
    canEnd: {
      type: Boolean,
      default: !1
    },
    skew: {
      type: Number,
      default: 0
    },
    disabledResize: {
      type: Boolean,
      default: !1
    },
    prePage: {
      type: Boolean,
      default: !1
    },
    nextPage: {
      type: Boolean,
      default: !1
    },
    detailMode: {
      type: Boolean,
      default: !0
    },
    // 是否有滚动条
    hasSlider: {
      type: Boolean,
      default: !0
    }
  },
  data () {
    return {
      startX: 0,
      startStamp: 0,
      moveStamp: 0,
      moving: !1,
      distanceX: 0,
      offsetX: 0,
      // 容器宽度
      wrapperW: 0,
      // 内容宽度
      contentW: 0,
      timer: null
    }
  },
  computed: {
    sliderMax () {
      return this.wrapperW - this.contentW
    },
    needSlide () {
      return this.contentW > this.wrapperW
    },
    slideWidth () {
      return this.wrapperW - this.skew
    }
  },
  watch: {
    autoIndex () {
      this.$nextTick(() => {
        this.handerResize()
      })
    },
    distanceX () {
      let t = this.offsetX + this.distanceX
      const tempT = t <= 0 ? t : 0
      if (tempT >= this.sliderMax) {
        t = tempT
      } else {
        t = this.sliderMax
      }

      if (this.distanceX !== 0) {
        this.moving = !0
        this.moveContent(t)
      }
    }
  },
  mounted () {
    if (this.canReset) {
      this.$on('RESET_SLIDER_STAT', () => {
        const $content = this.$el.children[0].children[0]
        if ($content) {
          $content.style.transition = 'none'
          this.moveContent(0, !0)
          this.offsetX = 0
          setTimeout(() => {
            $content.style.transition = 'transform .3s ease'
          }, 100)
        }
      })
      this.$on('SLIDER_TO_INDEX', () => {
        if (this.autoIndex > 0) {
          const distance = -(this.contentW / this.length) * (this.autoIndex - 0.2)
          this.offsetX = distance < this.sliderMax ? this.sliderMax : distance
          this.moveContent(this.offsetX)
        } else {
          this.$emit('RESET_SLIDER_STAT')
        }
      })
    }

    if (this.canEnd) {
      this.$on('SLIDER_TO_END', () => {
        const $content = this.$el.children[0].children[0]
        if ($content) {
          $content.style.transition = 'none'
          this.moveContent(this.sliderMax, !0)
          this.offsetX = this.sliderMax
          setTimeout(() => {
            $content.style.transition = 'transform .3s ease'
          }, 100)
        }
      })
    }

    this.wrapperW = this.$el.offsetWidth
    window.addEventListener('resize', this.handerResize, !1)
  },
  updated () {
    if (this.detailMode) {
      this.contentW = this.$el.children[0].children[0].scrollWidth
      if (!flag && this.needSlide && this.autoIndex > 0) {
        const distance = -(this.contentW / this.length) * (this.autoIndex - 0.2)
        this.offsetX = distance < this.sliderMax ? this.sliderMax : distance
        this.moveContent(this.offsetX)
        flag = !0
      }
      this.$emit('ready', this.needSlide)
    }
  },
  methods: {
    handerResize () {
      if (this.detailMode) {
        this.wrapperW = this.$el.offsetWidth
        this.contentW = this.$el.children[0].children[0].scrollWidth
        if (this.needSlide && this.autoIndex > 0) {
          const distance = -(this.contentW / this.length) * (this.autoIndex - 0.2)
          this.offsetX = distance < this.sliderMax ? this.sliderMax : distance
          this.moveContent(this.offsetX)
        } else {
          if (this.needSlide && !this.disabledResize) {
            this.offsetX = 0
            this.moveContent(0)
          }
        }
      }
    },
    onTouchstart (event) {
      if (this.needSlide && this.slideType === 'touch') {
        event.stopPropagation()
        this.clearTimer()
        this.initData()
        if (this.needSlide && event.touches.length === 1) {
          document.body.addEventListener('touchmove', this.preventScroll, !!window.supportPassive && {
            passive: !1
          })
        }
        this.startStamp = event.timeStamp
        this.startX = event.touches[0].clientX
      }
    },
    onTouchmove (event) {
      if (this.needSlide && this.startX !== 0 && this.slideType === 'touch') {
        event.preventDefault()
        this.moveStamp = event.timeStamp
        this.distanceX = event.changedTouches[0].clientX - this.startX
      }
    },
    onTouchend (event) {
      if (this.slideType === 'touch') {
        if (this.needSlide && event.timeStamp - this.moveStamp < 30) {
          const i = this.distanceX / (event.timeStamp - this.startStamp)
          this.autoSlide(i, () => {
            this.initData()
          })
        } else {
          this.initData()
          document.body.addEventListener('touchmove', this.preventScroll, !!window.supportPassive && {
            passive: !1
          })
        }
      }
    },
    // 向前滑动
    slidePrev () {
      if (!this.timer) {
        this.$emit('clickpre')
        if (this.offsetX < 0 && this.timer === null) {
          this.distanceX = this.slideWidth
          this.timer = setTimeout(() => {
            this.offsetX += this.slideWidth
            this.offsetX > 0 && (this.offsetX = 0)
            this.distanceX = 0
            this.clearTimer()
          }, 300)
        } else {
          this.prePage && this.$emit('pagepre')
        }
      }
    },
    // 向后滑动
    slideNext () {
      if (!this.timer) {
        this.$emit('clicknext')
        if (this.offsetX > this.sliderMax && this.timer === null) {
          this.distanceX = -this.slideWidth
          this.timer = setTimeout(() => {
            this.offsetX -= this.slideWidth
            this.offsetX < this.sliderMax && (this.offsetX = this.sliderMax)
            this.distanceX = 0
            this.clearTimer()
          }, 300)
        } else {
          this.nextPage && this.$emit('pagenext')
        }
      }
    },
    clearTimer () {
      this.timer && clearInterval(this.timer)
      this.timer = null
    },
    autoSlide (distance, fn) {
      if (!this.timer) {
        var n = Math.abs(distance)
        this.timer = setInterval(() => {
          if (distance > 0) {
            this.distanceX = this.distanceX + 35 * distance
            distance -= n / 35
            if (distance <= 0) {
              distance = 0
            }
          } else if (distance < 0) {
            this.distanceX = this.distanceX + 35 * distance
            distance += n / 35
            if (distance >= 0) {
              distance = 0
            }
          } else {
            fn && fn()
            this.clearTimer()
          }
        }, 10)
      }
    },
    moveContent (distance, e) {
      const $content = this.$el.children[0].children[0]
      if ($content) {
        $content.style.transform = `translate3d(${distance}px, 0, 0)`
        $content.style.webkitTransform = `translate3d(${distance}px, 0, 0)`
      }
      const left = (distance / this.sliderMax * (this.wrapperW - 90))
      this.$el.children[1].children[0].style.left = `${left}px`
    },
    initData () {
      this.startStamp = 0
      this.moveStamp = 0
      const distance = this.offsetX + this.distanceX
      if (this.distanceX > 0) {
        this.offsetX = distance <= 0 ? distance : 0
      } else {
        this.offsetX = distance >= this.sliderMax ? distance : this.sliderMax
      }
      this.distanceX = 0
      this.startX = 0
      this.moving = !1
    },
    preventScroll (event) {
      event.cancelable && !event.defaultPrevented && event.preventDefault()
    },
    moveTostart () {
      const $content = this.$el.children[0].children[0]
      if ($content) {
        $content.style.transition = 'none'
        this.moveContent(0, !0)
        this.offsetX = 0
        setTimeout(() => {
          $content.style.transition = 'transform .3s ease'
        }, 100)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
  .slider{
    &-wrap{
      position: relative;
      width: 100%;
    }
    &-content{
      overflow: hidden;
    }
    &-control{
      position: relative;
      height: rem(2.5px);
      .control-item{
        position: absolute;
        top: 0;
        min-width: rem(5px);
        width: rem(90px);
        height: rem(2.5px);
        border-radius: rem(1.5px);
        background-color: rgba(0,0,0,.2);
      }
    }
  }
</style>
